#!/usr/bin/env python
# -*- coding: utf-8 -*-

import threading
import thread
import SocketServer
import MysqlUtils
import DataTool
import datetime
import Config
import time

# 线程锁
mutex = threading.RLock()
local_data = threading.local()


class ThreadedUDPRequestHandler(SocketServer.BaseRequestHandler):
    """
    请求处理的handler
    """
    def handle(self):
        try:
            local_data.data = self.request[0]
            local_data.socket = self.request[1]
            print time.ctime(), threading.current_thread().name
            # 分析请求的数据
            # 上锁
            mutex.acquire()
            try:
                local_data.analysis = DataTool.Analysis(local_data.data)
            except Exception as e:
                print '第一个锁处发生异常', e
                mutex.release()
                thread.exit()
            # 释放锁
            mutex.release()
            local_data.check_result = 'failure'
            if local_data.analysis.check_crc():
                # 系统类型
                local_data.sys_type = local_data.analysis.get_sys_type()
                # 指令类型
                local_data.order_type = local_data.analysis.get_order_type()
                # 集中器ID
                local_data.cid = local_data.analysis.get_id()
                # 集中器密码
                local_data.concentrator_password = local_data.analysis.get_concentrator_passwod()
                if local_data.order_type == '1':
                    local_data.phone = local_data.analysis.get_phone()
                    print '----------------------------'
                    print '系统类型：' + local_data.sys_type
                    print '指令类型：' + local_data.order_type
                    print 'ID号：' + local_data.cid
                    print '集中器密码：' + local_data.concentrator_password
                    print '手机号：' + local_data.phone
                    print '----------------------------'
                    # 存入解析的内容到数据库
                    local_data.db = MysqlUtils.MysqlHelper()
                    local_data.cno_count = \
                    local_data.db.query("SELECT COUNT(cno) as cno_count FROM natgas_concentratorreg WHERE cno='%s'" % (local_data.cid))[0][
                        'cno_count']
                    if local_data.cno_count == 0:
                        local_data.db.dml("INSERT INTO natgas_concentratorreg(sys_type, order_type, cno, cpass, phone, add_time) "
                               "VALUES('%s', '%s', '%s', '%s', '%s', now())"
                               % (local_data.sys_type, local_data.order_type, local_data.cid, local_data.concentrator_password, local_data.phone))
                    else:
                        local_data.db.dml("UPDATE natgas_concentratorreg SET order_type='%s' WHERE cno='%s'" % (local_data.order_type, local_data.cid))
                    local_data.db.close()
                    local_data.check_result = local_data.analysis.get_ack('reg')
                elif local_data.order_type == '3':
                    # 数据包里面的集中器密码就是集中器ID
                    local_data.cid = local_data.concentrator_password
                    local_data.control_field_tag = local_data.analysis.get_control_field_tag()
                    local_data.control_field_pack = local_data.analysis.get_control_field_pack()
                    local_data.curdata_num = local_data.analysis.get_curdata_num()
                    local_data.flowmeter_num = local_data.analysis.get_flowmeter_num()
                    local_data.flowmeter_data = local_data.analysis.get_flowmeter_data()
                    print('----------------------------')
                    print('系统类型：' + local_data.sys_type)
                    print('指令类型：' + local_data.order_type)
                    print('ID号：' + local_data.cid)
                    print('集中器密码：' + local_data.concentrator_password)
                    print('控制信息[控制标志]：' + local_data.control_field_tag)
                    print('控制信息[数据包信息]：' + local_data.control_field_pack)
                    print('当前数据包帧号：' + local_data.curdata_num)
                    print('流量计数量：' + local_data.flowmeter_num)
                    for (i, local_data.flowmeter) in enumerate(local_data.flowmeter_data):
                        local_data.flowmeter_id = local_data.flowmeter['flowmeter_id']
                        local_data.flowmeter_type = local_data.flowmeter['flowmeter_type']
                        local_data.flowmeter_total_g = local_data.flowmeter['total_g']
                        local_data.flowmeter_total_b = local_data.flowmeter['total_b']
                        local_data.flowmeter_g = local_data.flowmeter['g']
                        local_data.flowmeter_b = local_data.flowmeter['b']
                        local_data.flowmeter_temperature = local_data.flowmeter['temperature']
                        local_data.flowmeter_pressure = local_data.flowmeter['pressure']
                        local_data.flowmeter_status = local_data.flowmeter['status']
                        print('流量计信息【流量计ID】：' + local_data.flowmeter_id)
                        print('流量计信息【协议类型】：' + local_data.flowmeter_type)
                        print('流量计信息【工况累积量】：' + local_data.flowmeter_total_g)
                        print('流量计信息【标况累积量】：' + local_data.flowmeter_total_b)
                        print('流量计信息【工况流量】：' + local_data.flowmeter_g)
                        print('流量计信息【标况流量】：' + local_data.flowmeter_b)
                        print('流量计信息【温度】：' + local_data.flowmeter_temperature)
                        print('流量计信息【压力】：' + local_data.flowmeter_pressure)
                        print('流量计信息【状态】：' + local_data.flowmeter_status)
                        # 暂时停用温度和压力都为0的筛选条件
                        # if local_data.flowmeter_temperature.strip() == '0.000' and local_data.flowmeter_pressure.strip() == '0.000':
                        #     print('温度和压力都为0，数据不正确，直接舍弃掉')
                        #     continue

                        # 保存数据库
                        local_data.db = MysqlUtils.MysqlHelper()
                        # 根据集中器ID和流量计ID找到对应的id号
                        # 上锁
                        mutex.acquire()
                        try:
                            local_data.concentrator = local_data.db.query("SELECT id FROM natgas_concentratorreg WHERE cno='%s'" % local_data.cid)
                            print threading.current_thread().name, "1：根据集中器ID得到集中器的信息"
                            if local_data.concentrator:
                                local_data.fid = local_data.db.query(
                                    "SELECT id, cno_id FROM natgas_flowmeterreg WHERE cno_id='%s' and flowmeter_id='%s'"
                                    %
                                    (local_data.concentrator[0]['id'], local_data.flowmeter_id)
                                )
                                print threading.current_thread().name, "2：根据集中器ID和流量计ID得到流量计的信息"
                                if len(local_data.fid) == 0:
                                    local_data.db.dml(
                                        "INSERT INTO natgas_flowmeterreg(flowmeter_id, cno_id, add_time) VALUES('%s', '%s', now())"
                                        %
                                        (local_data.flowmeter_id, local_data.concentrator[0]['id'])
                                    )
                                    print threading.current_thread().name, "3：插入新的流量计信息"
                                    local_data.fid = local_data.db.query(
                                        "SELECT id, cno_id FROM natgas_flowmeterreg WHERE cno_id='%s' and flowmeter_id='%s'"
                                        %
                                        (local_data.concentrator[0]['id'], local_data.flowmeter_id)
                                    )
                                    print threading.current_thread().name, "4：根据集中器ID和流量计ID得到流量计的信息"
                            else:
                                print threading.current_thread().name, '该集中器还没有注册'
                                continue
                            if local_data.fid:
                                local_data.fid = local_data.fid[0]
                            else:
                                print threading.current_thread().name, '没有查到对应的流量计信息'
                                continue
                        except Exception as e:
                            print '第二个锁处发生异常', e
                            mutex.release()
                            thread.exit()
                        # 插入接收到的流量计信息（向当月的数据表插入）
                        local_data.db.dml(
                            "INSERT INTO natgas_flowmeterdata(flowmeter_id, flowmeter_type, flowmeter_total_g, "
                            "flowmeter_total_b, flowmeter_g, flowmeter_b, flowmeter_temperature, flowmeter_pressure, "
                            "flowmeter_status, add_time) "
                            "VALUES('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', now())"
                            %
                            (
                                local_data.fid['id'], local_data.flowmeter_type, local_data.flowmeter_total_g, local_data.flowmeter_total_b,
                                local_data.flowmeter_g, local_data.flowmeter_b, local_data.flowmeter_temperature, local_data.flowmeter_pressure, local_data.flowmeter_status
                            )
                        )
                        # 插入接收到的流量计信息（向最近2日内的数据表插入）
                        local_data.db.dml(
                            "INSERT INTO natgas_flowmeterdatatoday(flowmeter_id, flowmeter_type, flowmeter_total_g, "
                            "flowmeter_total_b, flowmeter_g, flowmeter_b, flowmeter_temperature, flowmeter_pressure, "
                            "flowmeter_status, add_time) "
                            "VALUES('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', now())"
                            %
                            (
                                local_data.fid['id'], local_data.flowmeter_type, local_data.flowmeter_total_g,
                                local_data.flowmeter_total_b,
                                local_data.flowmeter_g, local_data.flowmeter_b, local_data.flowmeter_temperature,
                                local_data.flowmeter_pressure, local_data.flowmeter_status
                            )
                        )
                        print threading.current_thread().name, "5：插入接收到的数据信息"
                        # 释放锁
                        mutex.release()
                        # 异常信息
                        # 读取短信设置的开关
                        if local_data.fid['cno_id']:
                            local_data.message_settings = local_data.db.query(
                                "SELECT message_switch,notify_condition,alert_freq,s.company_id FROM "
                                "natgas_flowmeterreg f, natgas_concentratorreg c, natgas_site s, "
                                "natgas_messagesettings m WHERE f.cno_id=c.id and c.site_id=s.id and "
                                "s.company_id=m.company_id and f.cno_id='%s'" % local_data.fid['cno_id']
                            )
                            print threading.current_thread().name, "6：查询短信通知开关"
                            if len(local_data.message_settings) > 0:
                                # 报警开关,1打开，0关闭
                                local_data.message_switch = local_data.message_settings[0]['message_switch']

                                if local_data.message_switch:
                                    # 获取当前时间小时数
                                    local_data.now_hour = datetime.datetime.now().hour
                                    # 获取不同时间段的上下限阈值并检测当前数据是否超出阈值
                                    local_data.m_list = local_data.db.query(
                                        "select * from natgas_monitortime where flowmeter_id ='%s'" % local_data.fid['id']
                                    )
                                    print threading.current_thread().name, "7：查询上下阈值"
                                    for m in local_data.m_list:
                                        if m['time_start'] <= local_data.now_hour <= m['time_end']:
                                            if float(local_data.flowmeter_temperature) > float(m['temperature_max']) or \
                                                            float(local_data.flowmeter_temperature) < float(m['temperature_min']) or \
                                                            float(local_data.flowmeter_pressure) > float(m['pressure_max']) or \
                                                            float(local_data.flowmeter_pressure) < float(m['pressure_min']) or \
                                                            float(local_data.flowmeter_g) > float(m['total_g_max']) or \
                                                            float(local_data.flowmeter_g) < float(m['total_g_min']) or \
                                                            float(local_data.flowmeter_b) > float(m['total_b_max']) or \
                                                            float(local_data.flowmeter_b) < float(m['total_b_min']):
                                                local_data.db.dml(
                                                    "INSERT INTO natgas_abnormaldata(flowmeter_id, flowmeter_type, "
                                                    "flowmeter_total_g, flowmeter_total_b, flowmeter_g, flowmeter_b, "
                                                    "flowmeter_temperature, flowmeter_pressure, flowmeter_status, add_time) "
                                                    "VALUES('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', now())"
                                                    %
                                                    (
                                                        local_data.fid['id'], local_data.flowmeter_type, local_data.flowmeter_total_g,
                                                        local_data.flowmeter_total_b, local_data.flowmeter_g, local_data.flowmeter_b, local_data.flowmeter_temperature,
                                                        local_data.flowmeter_pressure, local_data.flowmeter_status
                                                    )
                                                )
                                                print threading.current_thread().name, "8：插入异常数据"
                        local_data.db.close()
                    print('----------------------------')
                    # 返回ack
                    local_data.check_result = local_data.analysis.get_ack('data')
            local_data.socket.sendto(local_data.check_result, self.client_address)
        except BaseException as e:
            print '最外层发生异常', e
            thread.exit()


class ThreadedUDPServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer):
    """
    多线程处理的UDP服务器
    """
    # 允许重用地址
    allow_reuse_address = True

if __name__ == "__main__":
    server = ThreadedUDPServer((Config.SERVER_HOST, Config.SERVER_PORT), ThreadedUDPRequestHandler)
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.start()
    print 'Bind UDP on 9999...'
